package felix.things.router.opc;

import felix.things.router.config.OpcUaConfig;
import felix.things.router.opc.conf.OpcUaServerConfiguration;
import felix.things.router.opc.external.MonitorWatcher;
import felix.things.router.opc.rpc.RpcProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OpcUaServiceImpl extends BaseOpcUaService implements CommandLineRunner {

    @Autowired
    private OpcUaConfig opcUaConfig;

    @Autowired
    private RpcProcessor rpcProcessor;

    private Map<String, OpcUaServerMonitor> monitors;

    @Autowired(required = false)
    private MonitorWatcher watcher;

    @Override
    public void run(String... args) throws Exception {
        if (opcUaConfig.isEnable()) {
            log.info("init...");
            try {
                init();
                start();
                checkConnection();
            } catch (Exception e) {
                log.error("OPC-UA service configuration failed!", e);
            }
        }
    }

    /**
     * 状态监控
     */
    private void checkConnection() {
        try {
            for (OpcUaServerMonitor monitor : monitors.values()) {
                monitor.checkConnection();
            }
        } catch (Exception e) {
            log.error("OPC-UA service checkConnection failed!", e);
            throw e;
        }
    }

    @Override
    public void init() throws Exception {
        try {
            monitors = opcUaConfig.getServers().stream().collect(
                    Collectors.toMap(OpcUaServerConfiguration::getApplicationName, c -> new OpcUaServerMonitor(watcher, rpcProcessor, c)));
        } catch (Exception e) {
            log.error("OPC-UA service initialization failed!", e);
            throw e;
        }
    }

    @Override
    public void start() throws Exception {
        try {
            for (OpcUaServerMonitor monitor : monitors.values()) {
                monitor.connect();
            }
        } catch (Exception e) {
            log.error("OPC-UA service started failed!", e);
            throw e;
        }
    }

    @Override
    public void destroy() {
        if (monitors != null) {
            monitors.values().forEach(OpcUaServerMonitor::disconnect);
        }
    }

    @Override
    public Map<String, OpcUaServerMonitor> getMonitors() {
        return monitors;
    }
}
